package com.leyou.search.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.clients.ItemClient;
import com.leyou.item.dto.*;
import com.leyou.search.pojo.Goods;
import com.leyou.search.repository.GoodsRepository;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static java.lang.Double.parseDouble;

@Service
public class IndexService {

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private GoodsRepository goodsRepository;

    /**
     * 把传入的spu转为goods,保存goods
     * @param spuDTO
     * @return
     */
    public Goods buildGoods(SpuDTO spuDTO){

        Goods goods = BeanHelper.copyProperties(spuDTO,Goods.class);

        //1.skus    id,title,price,image
        //跨服务查询skus
        List<SkuDTO> skuDTOS = this.itemClient.querySkuBySpuId(spuDTO.getId());

        //获取每个sku的price价格
        Set<Long> skuPrice  = new HashSet<>();

        //将sku表中数据 id,title,price,image 转换成 List<Map>
        List<Map<String,Object>> skus = new ArrayList<>();
        skuDTOS.forEach(skuDTO -> {
            Map<String,Object> sku = new HashMap<>();

            sku.put("id",skuDTO.getId());
            sku.put("title",skuDTO.getTitle());
            sku.put("price",skuDTO.getPrice());
            //sku图片只要一个值，但是原始的有多个图片，以，分隔
            sku.put("image",StringUtils.substringBefore(skuDTO.getImages(),","));
            skus.add(sku);

            skuPrice.add(skuDTO.getPrice());
        });
        goods.setSkus(JsonUtils.toString(skus));

        //2.all
        // 所有需要被搜索的信息，包含spu标题，分类，甚至品牌
        StringBuilder stringBuilder = new StringBuilder();
        //2.1 取出spu的名称（标题）
        stringBuilder.append(spuDTO.getName());

        //2.2 跨服务查询分类名称，3个级别的分类名，用" "分隔
        //TODO 缓存，如果redis中有，不用跨服务查询
        List<CategoryDTO> categoryDTOS = this.itemClient.queryCategoryByIds(spuDTO.getCategoryIds());
        //获取三个级别的分类名
        String names = categoryDTOS.stream()
                .map(CategoryDTO::getName)
                .collect(Collectors.joining(" "));
        stringBuilder.append(" "+ names);
        goods.setAll(stringBuilder.toString());


        //3.category
        goods.setCategoryId(spuDTO.getCid3());


        //4.createTime
        goods.setCreateTime(spuDTO.getCreateTime().getTime());


        //5.price
        goods.setPrice(skuPrice);


        //6.specs   key = name：value = 通用、特有规格（根据spuParam表中generic  0/1  判断value = generic_spec/special_spec）
        //6.1 获取到，所有的可搜索规格参数，

        //跨服务查询当前分类下，所有的可搜索规格参数
        List<SpecParamDTO> specParamDTOS = this.itemClient.querySpecParams(null, spuDTO.getCid3(), true);
        //根据spuId获取对应spuDetail
        SpuDetailDTO spuDetailDTO = this.itemClient.querySpuDetailBySpuId(spuDTO.getId());

        //6.2 以可搜索规格参数的名称为key，以其值为value就行数据保存（spuDetail,genericSpec,specailSpec）
        //把通用规格的String的json转为map，转换方法两个参数，1，json，2：目标类型
        Map<Long, Object> genericMap = JsonUtils.nativeRead(spuDetailDTO.getGenericSpec(), new TypeReference<Map<Long, Object>>() {
        });
        //把特有规格转为map
        Map<Long, List<String>> specialMap = JsonUtils.nativeRead(spuDetailDTO.getSpecialSpec(), new TypeReference<Map<Long, List<String>>>() {
        });
        //specs表示所有的可搜索规格参数的信息 eg: CPU品牌:麒麟，网络制式：5G
        HashMap<String, Object> specs = new HashMap<>();

        //循环把可搜索规格参数加入specs，key就是规格参数的名称
        specParamDTOS.forEach(specParamDTO -> {
            //获取规格参数id
            Long id = specParamDTO.getId();

            //获取规格参数名称
            String name = specParamDTO.getName();

            Object value = null;
            if (specParamDTO.getGeneric()){//通用规格
                value = genericMap.get(id);
            }else {//特有规格
                value = specialMap.get(id);
            }

            //如果是数值类型，需要选择区间
            if (specParamDTO.getNumeric()){
                value = chooseSegment(value,specParamDTO);
            }

            //规格参数名称作为key，对应的值作为value
            specs.put(name,value);
        });

        goods.setSpecs(specs);
        return goods;
    }

    /**
     * 对数值类型的数据进行区间的选择
     * 利用传递的数值，经过查询对应的含有区间的字段，找到对应的区间
     * @param value
     * @param p specParamDTO
     * @return
     */
    private String chooseSegment(Object value, SpecParamDTO p) {
        if (value == null || StringUtils.isBlank(value.toString())) {
            return "其它";
        }
        double val = parseDouble(value.toString());
        String result = "其它";
        // 保存数值段
        for (String segment : p.getSegments().split(",")) {
            String[] segs = segment.split("-");
            // 获取数值范围
            double begin = parseDouble(segs[0]);
            double end = Double.MAX_VALUE;
            if (segs.length == 2) {
                end = parseDouble(segs[1]);
            }
            // 判断是否在范围内
            if (val >= begin && val < end) {
                if (segs.length == 1) {
                    result = segs[0] + p.getUnit() + "以上";
                } else if (begin == 0) {
                    result = segs[1] + p.getUnit() + "以下";
                } else {
                    result = segment + p.getUnit();
                }
                break;
            }
        }
        return result;
    }

    private double parseDouble(String str) {
        try {
            return Double.parseDouble(str);
        } catch (Exception e) {
            return 0;
        }
    }

    /**
     * 新增索引
     * @param id
     */
    public void createIndex(Long id) {

        SpuDTO spuDTO = this.itemClient.querySpuById(id);

        Goods goods = buildGoods(spuDTO);

        this.goodsRepository.save(goods);
    }

    /**
     * 删除索引
     * @param id
     */
    public void deleteById(Long id) {

        this.goodsRepository.deleteById(id);
    }

}
